package cn.jofei.core.bean;

import cn.jofei.common.exception.BootException;
import cn.jofei.common.util.Utils;
import cn.jofei.core.Invoker;
import cn.jofei.core.container.Container;

import java.lang.reflect.Constructor;

/**
 * BeanFactory
 *
 * @author Jofei Bao
 * @version ngbao v2.0
 * @date 2022年10月26日 11:52
 */
public abstract class BeanFactory implements Container {

    public static Object getBean(String beanName) {
        BeanDefined defined = BEAN_BEAN_DEFINED_MAPPING.get(beanName);
        if (defined != null) {
            return instance(defined);
        } else {
            throw new BootException(String.format("未找到beanName: %s", beanName));
        }
    }

    public static <T> T getBean(Class<T> tClass) {
        try {
            return (T) getBean(Invoker.beanName(tClass));
        } catch (Exception e) {
            throw new BootException(String.format("未找到类：%s对应的bean", tClass));
        }
    }

    protected static Object instance(BeanDefined defined) {
        if (BEAN_NAME_BEAN_MAPPING.containsKey(defined.getName())) {
            return BEAN_NAME_BEAN_MAPPING.get(defined.getName());
        } else {
            try {
                Object instance;
                //构造器注入
                if (defined.getConstructClasses() != null) {
                    Constructor<?> constructor = defined.getClazz().getDeclaredConstructor(defined.getConstructClasses());
                    Object[] constructArgs = new Object[defined.getConstructClasses().length];
                    for (int i = 0; i < defined.getConstructClasses().length; i++) {
                        Class<?> constructClass = defined.getConstructClasses()[i];
                        String beanName = CLASS_BEAN_MAPPING.get(constructClass);
                        if (Utils.isNull(beanName)) {
                            throw new BootException(String.format("名称为：%s的Bean未找到，Class：%s", beanName, constructClass));
                        } else {
                            BeanDefined beanDefined = BEAN_BEAN_DEFINED_MAPPING.get(beanName);
                            constructArgs[i] = instance(beanDefined);
                        }
                    }
                    instance = constructor.newInstance(constructArgs);
                } else {
                    Constructor<?> constructor = defined.getClazz().getDeclaredConstructor();
                    instance = constructor.newInstance();
                }
                //添加class BEAN_NAME 映射容器
                CLASS_BEAN_MAPPING.putIfAbsent(defined.getClazz(), defined.getName());
                Class<?> superclass = defined.getClazz().getSuperclass();
                if (superclass != null) {
                    CLASS_BEAN_MAPPING.putIfAbsent(superclass, defined.getName());
                }
                //添加实例容器
                BEAN_NAME_BEAN_MAPPING.putIfAbsent(defined.getName(), instance);
                return BEAN_NAME_BEAN_MAPPING.get(defined.getName());
            } catch (Exception e) {
                throw new BootException(e);
            }
        }
    }
}
